//chatter_serv.c
//the slave thread's first job


#include "chatter_serv.h"
#include "chatter_err_log.h"
#include "chatter_global.h"
#include "md5.h"
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

int query_db(const char *statement, MYSQL_RES **res, int *num_row, int *num_field , long *affect_r)
{

	pthread_mutex_lock( &database_mutex);			//lock

	if(mysql_query(conn, statement))
	{
		err_msg(mysql_error(conn));
		pthread_mutex_unlock( &database_mutex);		//unlock and return
		return -1;
	}

	*res = mysql_store_result(conn);

	if(affect_r != NULL)
		*affect_r = mysql_affected_rows(conn);

	pthread_mutex_unlock( &database_mutex);			//unlock

	if(*res)
	{//there are rows
		if(num_row != NULL)
			*num_row	= mysql_num_rows(*res);
		if(num_field != NULL)
			*num_field	= mysql_num_fields(*res);
	}
	else
	{//empty set
		if(num_row != NULL)
			*num_row = 0;
		if(num_field != NULL)
			*num_field = 0;
	}

	return 0;
}

void * ctrl_center(void * arg)
{
	int				result;
	short			length;
	packet_header_t	pc_hd;
	char			pc_bd[1024] = {0};			//the largest packet recv from client is msg ,so 1024 is enough
	func_index_t	func_index[FUNC_NUM];	//array of functions(this functions all use FLAG_xxx)

	const int sockfd = (int) arg;
	result = func_index_init(func_index);
	if(result == -1)
	{
		err_msg("can't init func index\n");
		write_log(LOG_SYS+LOG_EE, "cant init func index");
	}

	while(1)
	{
		result = recv(sockfd, &pc_hd, sizeof(packet_header_t), 0);
		if(result == -1)
		{
			err_msg("In ctrl_center()_chatter_serv.c_recv:%m\n");
		}
		length = ntohs(pc_hd.length);				//Network byte-order to Host byte-order

		if(length > 1024 )
		{
			send_succ_or_err(sockfd, FLAG_FAILURE_TOO_LARGE, NULL, 0);
			continue;	
		}
		
		if(length > 0)								//some packets such as HELO packet,doesn't have body,and LENGTH ==0
			result = recv(sockfd, pc_bd, length, 0);				//get body

		if(result == -1)
		{
			err_msg("In ctrl_center()_chatter_serv.c_recv:%m\n");
		}
		
		int counter = 0;
		while( counter < FUNC_NUM)
		{
			if(func_index[counter].index == pc_hd.flag )				//found the index matching FLAG
			{
				if(func_index[counter].fptr(sockfd, pc_bd, length) < 0)
				{
					err_msg("process FLAG:%d, sockfd:%d\n", pc_hd.flag, sockfd);
					write_log(LOG_SYS+LOG_WW, "err while process FLAG:%d on socket:%d", pc_hd.flag, sockfd);
				}
				break;
			}
			counter ++;
		}
		
		if(counter == FUNC_NUM)
			send_succ_or_err(sockfd, FLAG_FAILURE_UNKNOWN, NULL, 0);

	}
	pthread_exit(NULL);
}


int send_succ_or_err(const int sockfd, const unsigned char flagvalue, const char *errstr, const size_t str_len)
{
	packet_header_t		packet;
	packet_err_t		body;
	
	packet.flag = flagvalue;
	if(flagvalue == FLAG_SUCCESS || errstr == NULL)
		packet.length = 0;
	else
	{
		packet.length = MAX_LEN_ERR;
		strncpy(body.err_str, errstr, str_len);
	}

	return(send(sockfd, &packet, sizeof(packet), 0));
	
}

int func_index_init(func_index_t *func_index)
{
	unsigned char flag[] = {
		FLAG_HELLO, 
		FLAG_LOGIN, 
		FLAG_LOGOUT, 
		FLAG_MESSAGE,
		FLAG_REQUEST_BUDDY_LIST, 
		FLAG_SEARCH_NUM, 
		FLAG_SEARCH_NICK,
		FLAG_ADD_A_BUDDY, 
		FLAG_DEL_A_BUDDY, 
		FLAG_SET_DETAIL,
		FLAG_REGISTER, 
		FLAG_SET_NICK
	};

	int (*func[])(int sockfd, char *body, short len) = {
		serv_hello,
		serv_login,
		serv_logout,
		serv_message,
		serv_request_buddy_list,
		serv_search_num,
		serv_search_nick,
		serv_add_a_buddy,
		serv_del_a_buddy,
		serv_set_detail,
		serv_register,
		serv_set_nick
	};
	
	int counter = 0;

	while(counter < FUNC_NUM)
	{
		(func_index[counter]).index = flag[counter];
		(func_index[counter]).fptr	= func[counter];
		counter ++;
	}
	
	return 0;
}

int serv_hello(int sockfd, char *body, short len)
{//it seems that server should ignore the parameter "body"
	packet_hello_t	hellopacket;
	
	hellopacket.header.flag = FLAG_HELLO;
	hellopacket.header.length = 0;

	return (len = (send(sockfd, &hellopacket, sizeof(hellopacket), 0)));		//to avoid warnning of unuse len

}

int serv_login( int sockfd, char *body, short len)
{

	MYSQL_RES*		sqlres;
	MYSQL_ROW		row;
	int				num_rows;
	char			sqlstatement[1024] = {'0'};
	char			err_str[40];
	packet_login_t	packet;
	char			logstatement[128];
	unsigned char	md5_sum[17] = {'\0'};
	unsigned char	tobe_digg[MAX_LEN_ACCOUNT + MAX_LEN_PASSWD];
	md5_state_t		pms;

	if(len != sizeof(packet_login_t))
			err_msg(" serv_login>>> packet size not match \n");

	memcpy(&packet, body, sizeof(packet_login_t));		//fillin packet<containing user account and password>

	/***** fillin sql query statement  ***/
		/****  discard this because I found sprintf()

		strcat(strcat(strcat(strcpy(sqlstatement, 
							"SELECT Aaccount FROM Auth WHERE Aaccount="),
						packet.from), 
					" AND Apasswd="), 
				packet.passwd);
		*/
	sprintf(sqlstatement,"SELECT Aaccount AND Apasswd FROM Auth WHERE Aaccount=%s ", packet.from);

	int result = query_db(sqlstatement, &sqlres, &num_rows, NULL, NULL);
	if(result == -1 )								//mysql_query error 
	{// send err packet and return -1
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		sprintf(logstatement, "database err while processing login:%s", packet.from);
		write_log(LOG_WW+LOG_SYS, logstatement);
		return -1;
	}
	if(num_rows == 0)
	{// Donot have this account
		strcpy(err_str, "account not exists in database, Are U registered?");
		send_succ_or_err(sockfd, FLAG_FAILURE_ACC_NO, err_str, sizeof(err_str));
		mysql_free_result(sqlres);
		printf("account %s login failed: wrong account ?\n", packet.from);
		return 0;
	}
	else
	{// check MD5SUM and if everything is OK, send succ packet(account and md5sum are all MATCHED)
		row = mysql_fetch_row(sqlres);
		strcpy((char *)tobe_digg, packet.from);
		strcat((char *)tobe_digg, row[1]);

		md5_init(&pms);
		md5_append(&pms, tobe_digg, strlen((char *)tobe_digg)); 
		md5_finish(&pms, md5_sum);

		if(strcmp(packet.md5sum, (char *)md5_sum) == 0)
		{
			send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);
			printf("account %s login ~~\n",packet.from);
			sprintf(logstatement, "account %s login ", packet.from);
			write_log(LOG_NOMARL+LOG___, logstatement);
		}
		else
		{
			strcpy(err_str, "password verifization failed");
			send_succ_or_err(sockfd, FLAG_FAILURE_PASSWD_NO, err_str, 0);
		}
	}
	mysql_free_result(sqlres);

	/**  update online-status , and update SOCKFD ***/
		/*
			strcat(strcpy(sqlstatement, "UPDATE Auth SET Aonline = TRUE, Asockfd = "), sockfd)
		*/
	sprintf(sqlstatement, "UPDATE Auth SET Aonline = TRUE, Asockfd = %d", sockfd);

	if(query_db(sqlstatement, &sqlres, NULL, NULL, NULL) == -1)
	{//client 应该设置运行层标志,以便对server任何时候发回的FLAG都能适当处理
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}

	mysql_free_result(sqlres);
	/*** get his online buddy's sockfd  ***/
		/**
		strcat(strcat(strcpy(sqlstatement,
						"SELECT Aaccount FROM Auth WHERE Aonline = TRUE AND Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = "),
					packet.from),
				" ) ");
		**/
	sprintf(sqlstatement, 
			"SELECT Asockfd FROM Auth WHERE Aonline=TRUE AND Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = %s)", 
			packet.from);

	result = query_db(sqlstatement, &sqlres, &num_rows, NULL, NULL);
	if(result == -1 )
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}

	if(num_rows == 0)
	{//no buddy, just ruturn to ctrl_center()
		mysql_free_result(sqlres);
		return 0;
	}

	/*** tell his online buddys that guy has login **/
	/* make a STATUS_ON packet */
	packet_header_t		header;			//only need a new header, and use [packet.from] to save a little mem	
	
	header.flag = FLAG_STATUS_ON;
	header.length = htons(MAX_LEN_ACCOUNT);

	int temp;
	while( (row = mysql_fetch_row(sqlres)) != NULL)
	{
		send(temp = atoi(row[0]), &header, sizeof(header), 0);
		send(temp, packet.from, sizeof(packet_status_on_t), 0);
	}

	printf("send status online[%s] packets done\n", packet.from);
	mysql_free_result(sqlres);
	return 0;
}

int		serv_logout( int sockfd, char *body, short len)
{

	MYSQL_RES*		sqlres;
	MYSQL_ROW		row;
	int				num_rows;
	char			sqlstatement[1024] = {'0'};
	packet_logout_t	packet;
	char			logstatement[128];

	if(len != sizeof(packet_logout_t))
		err_msg(" serv_logout>>> packet size not matched\n");

	memcpy(&packet, body, sizeof(packet_logout_t));		//fillin packet<containing user account and password>

	printf("account %s logout ~~\n",packet.from);
	sprintf(logstatement, "account %s logout~~ ", packet.from);
	write_log(LOG_NOMARL+LOG___, logstatement);

	/**  update online-status , and update SOCKFD ***/
		/*
			strcat(strcpy(sqlstatement, "UPDATE Auth SET Aonline = TRUE, Asockfd = "), sockfd)
		*/
	sprintf(sqlstatement, "UPDATE Auth SET Aonline = FALSE, Asockfd = %d", -1);

	if(query_db(sqlstatement, &sqlres, NULL, NULL, NULL) == -1)
	{//
		sprintf(logstatement, "database error while process [%s] logout", packet.from);
		write_log(LOG_EE+LOG_SYS, logstatement);
		close(sockfd);
		return -1;
	}

	mysql_free_result(sqlres);
	/*** get his online buddy's sockfd  ***/
		/**
		strcat(strcat(strcpy(sqlstatement,
						"SELECT Aaccount FROM Auth WHERE Aonline = TRUE AND Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = "),
					packet.from),
				" ) ");
		**/
	sprintf(sqlstatement, 
			"SELECT Asockfd FROM Auth WHERE Aonline=TRUE AND Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = %s)",
			packet.from);

	int result = query_db(sqlstatement, &sqlres, &num_rows, NULL, NULL);
	if(result == -1 )
	{
		sprintf(logstatement, "database error while process [%s] logout", packet.from);
		write_log(LOG_EE+LOG_SYS, logstatement);
		close(sockfd);
		return -1;
	}

	if(num_rows == 0)
	{//no buddy is online; just ruturn to ctrl_center()
		mysql_free_result(sqlres);
		close(sockfd);
		return 0;
	}

	/*** tell his online buddys that guy has go to bed **/
	/* make a STATUS_OFF packet */
	packet_header_t		header;			//ofcourse use the old packet as body
	
	header.flag = FLAG_STATUS_OFF;
	header.length = htons(MAX_LEN_ACCOUNT);

	int temp;
	while( (row = mysql_fetch_row(sqlres)) != NULL)
	{
		send(temp = atoi(row[0]), &header, sizeof(header), 0);
		send(temp, packet.from, sizeof(packet_status_off_t), 0);
	}

	printf("send status offline[%s] packets done\n", packet.from);
	mysql_free_result(sqlres);

	close(sockfd);
	return 0;
}

int		serv_message( int sockfd, char *body , short len)
{
	MYSQL_RES*				sqlres;
	MYSQL_ROW				row;
	int						num_rows;
	char					sqlstatement[1024] = {'0'};
	packet_message_header_t	packet;
	char					logstatement[128];
	char					err_str[40];
	int						counter = 0;				//used in while()
	int						result;

	memcpy(&packet, body, sizeof(packet_message_header_t));		//fillin packet<containing from & to>

#ifdef	_DEBUG_CHATTER_SERV
	sprintf(logstatement, "account %s try sending a msg to %s ",packet.from, packet.to);
	printf("%s\n", logstatement);
	write_log(LOG_NOMARL+LOG___, logstatement);
#endif
	while(counter < 2)
	{

		if(counter == 0 )
		{/*** check if this guy has that buddy ***/
			sprintf(sqlstatement, "SELECT Bbuddy FROM Buddylist WHERE Bself =%s, Bbuddy=%s", 
					packet.from, packet.to);
		}
		else
		{/*** get [packet.to]'s sockfd(if it's online) **/
			sprintf(sqlstatement, "SELECT Asockfd FROM Auth WHERE Aaccount=%s AND Aonline=TRUE",
					packet.to);
		}

		if(counter != 0)
			mysql_free_result(sqlres);
		result = query_db(sqlstatement, &sqlres, &num_rows, NULL, NULL);

		if(result == -1 )
		{
			if(counter == 0)
				sprintf(logstatement, "database error while query [%s] buddylist", packet.from);
			else
				sprintf(logstatement, "database err while qurey [%s]'s online status", packet.to);
			write_log(LOG_EE+LOG_SYS, logstatement);
			strcpy(err_str, "database error @ server, it's not your fault");
			send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
			return -1;
		}

		if(num_rows == 0)
		{//Do not have this buddy, or that's not online, send an ERROR PACKET, and ruturn to ctrl_center()
			mysql_free_result(sqlres);
			if(counter == 0)
				send_succ_or_err(sockfd, FLAG_FAILURE_BUDDY_NO, NULL, 0); 
			else
				send_succ_or_err(sockfd, FLAG_FAILURE_BUDDY_OFF, NULL, 0);
			return 0;
		}
		counter ++;

	}

	/* send this MESSAGE PACKET to his buddy */
	packet_header_t		header;
	
	header.flag = FLAG_MESSAGE;
	header.length = htons(len);

	struct tm	*now = (struct tm *) time(NULL);
	now	=	localtime((time_t *) now);
	
	/*** MESSAGE from SERVER should include the time ****/
	packet.time.day		= (char) now->tm_mday;
	packet.time.hour	= (char) now->tm_hour;
	packet.time.minute	= (char) now->tm_min;
	packet.time.second	= (char) now->tm_sec;

	int temp;
	while( (row = mysql_fetch_row(sqlres)) != NULL)
	{
		send(temp = atoi(row[0]), &header, sizeof(header), 0);
		send(temp, body, len, 0);
	}

#ifdef _DEBUG_CHATTER_SERV
	printf("message from [%s], to [%s] send done\n", packet.from, packet.to);
#endif
	mysql_free_result(sqlres);

	close(sockfd);
	return 0;
}

int		serv_request_buddy_list( int sockfd, char *body , short len)
{
	MYSQL_RES*					sqlres;
	MYSQL_ROW					row;
	int							num_rows;
	int							num_fields;
	char						sqlstatement[1024] = {'0'};
	char						logstatement[128];
	char						err_str[40];
	packet_request_buddy_list_t	packet;

	if(len != sizeof(packet_request_buddy_list_t))
		err_msg(" serv_request_buddy_list>>> packet size not matched, account[%s]\n", packet.from);

	memcpy(&packet, body, sizeof(packet_request_buddy_list_t));		//fillin packet<containing user account >

#ifdef _DEBUG_CHATTER_SERV
	printf("account %s request buddylist ~~\n",packet.from);
#endif
	
	/********** GET it's buddylist  ************/
	sprintf(sqlstatement, 
			"SELECT Aaccount , Anickname , Aonline FROM Auth WHERE Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = %s)",
			packet.from);

	if(query_db(sqlstatement, &sqlres, &num_rows , &num_fields, NULL) == -1)
	{//
		sprintf(logstatement, "database error while process [%s] get_buddylist", packet.from);
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		write_log(LOG_EE+LOG_SYS, logstatement);
		return -1;
	}
	
	/******** MAKE a buddy list packet *****/

	packet_reponse_buddy_list_header_t		header;			//the buddylist's header
	
	header.header.flag = FLAG_RESPONSE_BUDDY_LIST;
	header.header.length = htons(sizeof(buddy_t) * num_rows);		//each buddy_t's size * buddy num

	send(sockfd, &header, sizeof(packet_reponse_buddy_list_header_t), 0);
	buddy_t		buddy;

	while((row = mysql_fetch_row(sqlres)) != NULL)
	{
			strcpy(buddy.account, row[0]);
			strcpy(buddy.nick, row[1]);
			buddy.online = row[2][0];
			send(sockfd, &buddy, sizeof(buddy_t), 0);
	}

#ifdef _DEBUG_CHATTER_SERV
	printf("send buddy list of [%s] done\n", packet.from);
#endif
	mysql_free_result(sqlres);
	return 0;
}

int		serv_search_num_nick(int sockfd, char *body, short len, const char flag)
{// flag:0-->num, 1--->nick
	MYSQL_RES*		sqlres;
	MYSQL_ROW		row;
	packet_search_t packet;
	int				num_row;
	int				num_field;
	int				result;
	char			sqlstatement[256];
	char			err_str[40];

	memcpy(&packet, body, sizeof(packet_search_t));

#ifdef _DEBUG_CHATTER_SERV
	printf("[%s] request detail of [%s]\n", packet.from, body+MAX_LEN_ACCOUNT);
#endif
	
	if(flag == 0)		//search num
		sprintf(sqlstatement, "SELECT * FROM Detail_All WHERE Daccount = %s", packet.content);
	else				//search nick
		sprintf(sqlstatement, "SELECT * FROM Detail_All WHERE Anickname = %s", packet.content);

	if(query_db(sqlstatement, &sqlres, &num_row, &num_field, NULL) < 0)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		err_msg("db error while processing [%s]'s seach request\n", packet.from);
		return -1;
	}
	
	/**** MAKE a DETAIL packet and send to client ***/
	packet_header_t				header;
	header.flag	= FLAG_RESPONSE_DETAIL;
	header.length = htons(sizeof(packet_response_detail_t));

	packet_response_detail_t	detail_packet;

	while((row = mysql_fetch_row(sqlres)) != NULL)
	{
		strcpy(detail_packet.detail.basic.account,	row[2]);
		strcpy(detail_packet.detail.basic.nick,		row[0]);
		strcpy(detail_packet.detail.registertime,	row[3]);
		strcpy(detail_packet.detail.birthday,		row[4]);
		strcpy(detail_packet.detail.contact,		row[5]);
		strcpy(detail_packet.detail.sex,			row[6]);
		detail_packet.detail.basic.online		=	row[1][0];
	}

	result = send(sockfd, &header, sizeof(header), 0) ; 
	if(result == -1 || (send(sockfd, &detail_packet, sizeof(detail_packet), 0) == -1))
	{
		err_msg("socket err while processing [%s] request [%s]'s detail\n", packet.from, row[3]);
	}	
#ifdef _DEBUG_CHATTER_SERV
	if(result != -1)
		printf("send detail to %s done\n", packet.from);
#endif
	
	mysql_free_result(sqlres);
	return result;
}

int		serv_search_num( int sockfd, char *body, short len)
{
	return serv_search_num_nick(sockfd, body, len, (char) 0);
}

int		serv_search_nick( int sockfd, char *body, short len)
{
	return serv_search_num_nick(sockfd, body, len, (char) 1);
}

int		serv_add_del_buddy(int sockfd, char *body, short len, const char flag)
{//flag:0-->add, 1--->del
	MYSQL_RES*				sqlres;
	MYSQL_ROW				row;
	char					sqlstatement[256];
	int						num_row;
	long					num_affected;				//this var is used to check "del"
	char					err_str[40];

	/***** this two packet has the same structure ****/
	packet_add_a_buddy_t	packet;

	memcpy(&packet, body, sizeof(packet));
	if(len != sizeof(packet))
	{
		err_msg("size not matched during [%s]'s add/del\n", packet.from);
		strcpy(err_str, "commumication error");
		send_succ_or_err(sockfd, FLAG_FAILURE, err_str, sizeof(err_str));
		return -1;
	}

	/***** query database  *****/
	if(flag == 0)
		sprintf(sqlstatement, "SELECT Aaccount FROM Auth WHERE Aaccount = %s", packet.account);
	else
		sprintf(sqlstatement, "SELECT Bself FROM Buddylist WHERE Bself = %s AND Bbuddy = %s", packet.from, packet.account);
	
	int  result = query_db(sqlstatement, &sqlres, &num_row, NULL, NULL);
	if(result == -1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		write_log(LOG_SYS + LOG_EE, "database error");
		return -1;
	}

	/****** send SUCC||FAIL packet and update DB  ***/
	if(num_row == 0)
	{//that account hasn't register|| not the guy's buddy
		if(flag == 0)
			send_succ_or_err(sockfd, FLAG_FAILURE_REG, NULL, 0);
		else
		{
			strcpy(err_str, "do not have this buddy in your list");
			send_succ_or_err(sockfd, FLAG_FAILURE, err_str, sizeof(err_str));
		}
		mysql_free_result(sqlres);
		return 0;
	}

	mysql_free_result(sqlres);
	if(flag == 0)
		sprintf(sqlstatement, "INSERT INTO Buddylist VALUES(%s, %s)", packet.from, packet.account );
	else
		sprintf(sqlstatement, "DELETE FROM Buddylist WHERE Bself = %s AND Bbuddy = %s", packet.from, packet.account);
	
	if(query_db(sqlstatement, &sqlres, NULL, NULL, &num_affected) < 0 || num_affected != 1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		err_msg("db err..too lazy to write why...\n");
		return -1;
	}
	else
		send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);

	mysql_free_result(sqlres);
	/******* if that's a ADD acction , send to the account has newly been added, if it's online ****/
	sprintf(sqlstatement, "SELECT Asockfd FROM Auth WHERE Aaccount = %s AND Aonline = TRUE", packet.account );
	query_db(sqlstatement, &sqlres, &num_row, NULL, NULL);
	if(num_row == 0)
	{//nothing to do 
		mysql_free_result(sqlres);
		return 0;
	}

	packet_header_t	header;
	header.flag = FLAG_ADD_A_BUDDY;
	header.length = htons(sizeof(packet));

	int temp;
	row = mysql_fetch_row(sqlres);
	send(temp = atoi(row[0]), &header, sizeof(header), 0);
	send(temp, &packet, sizeof(packet), 0);

	mysql_free_result(sqlres);
	return 0;
}

int		serv_add_a_buddy( int sockfd, char *body, short len)
{
	return serv_add_del_buddy(sockfd, body, len, (char) 0);
}

int		serv_del_a_buddy( int sockfd, char *body, short len)
{
	return serv_add_del_buddy(sockfd, body, len, (char) 1);
}

int		serv_set_detail( int sockfd, char *body, short len)
{
	MYSQL_RES*				sqlres;
	packet_set_detail_t		packet;
	char					err_str[40];

	memcpy(&packet, body, sizeof(packet_set_detail_t));
	if(sizeof(packet_set_detail_t) != len)
	{
		err_msg("size doesn't match: [%s] set detail\n", packet.detail.basic.account);
		strcpy(err_str, "commumication error");
		send_succ_or_err(sockfd, FLAG_FAILURE, err_str, sizeof(err_str));
		return -1;
	}

	/**** check if already has detail in database  ****/
	char	sqlstatement[1024];
	int		num_row;
	long	num_affected;

	sprintf(sqlstatement, "SELECT * FROM Detail_All WHERE Daccount = %s", packet.detail.basic.account);
	if(query_db(sqlstatement, &sqlres, &num_row, NULL, NULL) == -1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}

	mysql_free_result(sqlres);
	int result;
	if(num_row == 0)
	{//hasn't it in table
		sprintf(sqlstatement, 
				"INSERT INTO Detail_All(Daccount, Dregistime, Dbirthday, Dcontact, Dsex) VALUES('%s', '%s', '%s', '%s', '%s')",
				packet.detail.basic.account, packet.detail.registertime, packet.detail.birthday,
				packet.detail.contact, packet.detail.sex);
	}
	else if(num_row == 1)
	{//already in table, need to modify
		sprintf(sqlstatement, 
				"UPDATE Detail_All SET Anickname='%s',Dregistime='%s',Dbirthday='%s',Dcontact='%s',Dsex='%s' WHERE Daccount=%s",
				packet.detail.basic.nick, packet.detail.registertime, packet.detail.birthday,
				packet.detail.contact,  packet.detail.sex, packet.detail.basic.account);
	}
	result = query_db(sqlstatement, &sqlres, NULL, NULL, &num_affected);

	if(result == -1 || num_affected != 1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}

	send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);
#ifdef _DEBUG_CHATTER_SERV
	printf("[%s] has set detail\n", packet.detail.basic.account);
#endif
	
	mysql_free_result(sqlres);
	return 0;

}

int		serv_register( int sockfd, char *body, short len)
{
	packet_register_t	packet;
	MYSQL_RES*			sqlres;
	char				err_str[40];

	if(len != sizeof(packet))
	{
		strcpy(err_str, "commumication error");
		send_succ_or_err(sockfd, FLAG_FAILURE, err_str, sizeof(err_str));
		return -1;
	}
	memcpy(&packet, body, sizeof(packet));

	/*** to see if that account has registered ***/
	int		num_row;
	char	sqlstatement[256];

	int result;
	sprintf(sqlstatement, "SELECT * FROM Auth WHERE Aaccount = %s", packet.account);
	result = query_db(sqlstatement, &sqlres, &num_row, NULL, NULL);
	if(result == -1 || num_row != 0)
	{
		if(result == -1)
		{
			strcpy(err_str, "database error @ server, it's not your fault");
			send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
			return -1;
		}
		else
		{
			send_succ_or_err(sockfd, FLAG_FAILURE_REG, NULL, 0);
			return 0;
		}
	}
	/**** INSERT IN TO *****/
	long		num_affected;
	sprintf(sqlstatement, "INSERT INTO Auth VALUES('%s', '%s', '%s', TRUE, %d)",
			packet.account, packet.password, packet.account, sockfd);
	result = query_db(sqlstatement, &sqlres, NULL, NULL, &num_affected);
	if(result == -1 || num_affected != 1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}
	else
		send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);
	mysql_free_result(sqlres);
	return 0;
}

int		serv_set_nick( int sockfd, char *body, short len)
{
	packet_set_nick_t	packet;
	MYSQL_RES*			sqlres;
	MYSQL_ROW			row;

	if(len != sizeof(packet))
	{
		err_msg("size not match~during set nick\n");
		send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);
		return -1;
	}
	memcpy(&packet, body, sizeof(packet));
	
	/***** update nick ******/
	char	sqlstatement[256];
	char	err_str[40];
	int		result;
	int		num_row;
	long	num_affected;

	sprintf(sqlstatement, "UPDATE Auth SET Anickname = '%s' WHERE Aaccount = %s",
			packet.nick, packet.from);
	result = query_db(sqlstatement, &sqlres, NULL , NULL, &num_affected);
	if(result == -1 || num_affected != 1)
	{//not succ
		err_msg("db_err while set nick of [%s]\n", packet.from);
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}
	send_succ_or_err(sockfd, FLAG_SUCCESS, NULL, 0);

	mysql_free_result(sqlres);
	/**** tell his online buddy that nick change ***/
	sprintf(sqlstatement, 
			"SELECT Asockfd FROM Auth WHERE Aonline = TRUE AND Aaccount IN (SELECT Bbuddy FROM Buddylist WHERE Bself = %s)",
			packet.from);
	if(query_db(sqlstatement, &sqlres, &num_row, NULL, NULL) == -1)
	{
		strcpy(err_str, "database error @ server, it's not your fault");
		send_succ_or_err(sockfd, FLAG_FAILURE_DB, err_str, sizeof(err_str));
		return -1;
	}

	packet_header_t		header;
	header.flag = FLAG_NICK_CHANGE;
	header.length = htons(sizeof(packet_nick_change_t));

	int tempsock;
	while((row = mysql_fetch_row(sqlres)) != NULL)
	{
		send(tempsock = atoi(row[0]), &header, sizeof(header), 0);
		send(tempsock, &packet, sizeof(packet), 0);
	}

	mysql_free_result(sqlres);
	return 0;
}

